package mil.af.amc.adpetracker.service;

import mil.af.amc.adpetracker.dao.AdpeAccountDao;
import mil.af.amc.adpetracker.dao.EquipmentItemDao;
import mil.af.amc.adpetracker.dao.MaintenanceEntryDao;
import mil.af.amc.adpetracker.dao.RosDao;
import mil.af.amc.adpetracker.model.*;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.sql.Date;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.List;
import java.util.Map;

/**
 * Implementation of ROS Service
 *
 * @author TSgt Jason Ferguson
 */
@Service("rosService")
public class RosServiceImpl implements RosService {

    private static final Log log = LogFactory.getLog(RosServiceImpl.class);

    private RosDao rosDao;

    @Autowired
    public void setRosDao(RosDao rosDao) {
        this.rosDao = rosDao;
    }

    private AdpeAccountDao adpeAccountDao;

    @Autowired
    public void setAdpeAccountDao(AdpeAccountDao adpeAccountDao) {
        this.adpeAccountDao = adpeAccountDao;
    }

    private EquipmentItemDao equipmentItemDao;

    @Autowired
    public void setEquipmentItemDao(EquipmentItemDao equipmentItemDao) {
        this.equipmentItemDao = equipmentItemDao;
    }

    private EquipmentItemService equipmentItemService;

    @Autowired
    public void setEquipmentItemService(EquipmentItemService equipmentItemService) {
        this.equipmentItemService = equipmentItemService;
    }

    private MaintenanceEntryDao maintenanceEntryDao;

    @Autowired
    public void setMaintenanceEntryDao(MaintenanceEntryDao maintenanceEntryDao) {
        this.maintenanceEntryDao = maintenanceEntryDao;
    }

    public Ros getById(int rosPackageId) {

        return rosDao.getById(rosPackageId);

    }

    public void createRos(Map map) throws ServiceException {

        Ros ros = new Ros();

        // Set ADPE Account
        int adpeAccountId = (Integer) map.get("adpeAccountId");
        AdpeAccount acct = adpeAccountDao.getById(adpeAccountId);
        ros.setAdpeAccount(acct);

        // Set type
        RosType type = RosType.values()[(Integer) map.get("packageType")];
        ros.setType(type);

        // Get package name
        String internalName = (String) map.get("packageName");
        ros.setInternalPackageName(internalName);

        // Set tracking number
        String trackingNumber = (String) map.get("trackingNumber");
        ros.setTrackingNumber(trackingNumber.toUpperCase());

        // Set ROS Officer
        String rosOfficer = (String) map.get("rosOfficer");
        ros.setRosOfficer(rosOfficer);

        // Set init date
        String initDate = (String) map.get("initDate");

        String dateFormatPattern = "dd-MMM-yyyy";
        SimpleDateFormat sdf = new SimpleDateFormat(dateFormatPattern);

        try {
            java.util.Date pDate = sdf.parse(initDate);
            ros.setInitDate(pDate);
        } catch (ParseException e) {
            log.debug("Bad date input: " + initDate, e);
            System.out.println("Bad date input: " + initDate);
        }

        rosDao.saveOrUpdate(ros);

        ros = rosDao.getByTrackingNumber(trackingNumber);

        Integer[] pkgItemId = (Integer[]) map.get("pkgItemId");
        for (int itemId: pkgItemId) {

            EquipmentItem item = equipmentItemDao.getById(itemId);

            if (item.getAssignedUser()!=null) {
                equipmentItemService.unassignItem(itemId);
            }

            ros.getIdentifiedItems().add(item);
            item.setRosPackage(ros);

            MaintenanceEntry maint = new MaintenanceEntry();
            maint.setEntryDate(new java.util.Date());
            maint.setItem(item);
            maint.setEntryText("Item added to ROS/Waiver package " + ros.getName() + " (Tracking Number: " + ros.getTrackingNumber() + ")");


            item.getMaintenanceEntries().add(maint);
            equipmentItemDao.save(item);
            maintenanceEntryDao.save(maint);

            rosDao.saveOrUpdate(ros);
        }


    }

    public Ros editRos(Map map) throws ServiceException {

        Integer rosId = (Integer) map.get("rosId");
        if (rosId == null) {
            throw new ServiceException("message.ros.id.null", "ROS ID null for edit ros");
        }

        Ros ros = rosDao.getById(rosId);
        if (ros == null) {
            throw new ServiceException("message.ros.notfound", "Unable to find ROS with id#" + rosId);
        }

        // Edit type
        int rosType = (Integer) map.get("packageType");
        ros.setType(RosType.values()[rosType]);

        // Edit tracking number
        ros.setTrackingNumber((String) map.get("trackingNumber"));

        // Edit ROS Officer
        ros.setRosOfficer((String) map.get("rosOfficer"));

        // Edit init date
        String initDate = (String) map.get("initDate");

        String dateFormatPattern = "dd-MMM-yyyy";
        SimpleDateFormat sdf = new SimpleDateFormat(dateFormatPattern);

        try {
            java.util.Date pDate = sdf.parse(initDate);
            ros.setInitDate(pDate);
        } catch (ParseException e) {
            log.debug("Bad date input: " + initDate, e);
            System.out.println("Bad date input: " + initDate);
        }

        Integer[] items = (Integer[]) map.get("pkgItemId");
        for(int itemId: items) {

            EquipmentItem item = equipmentItemDao.getById(itemId);

            if (item.getAssignedUser()!=null) {
                equipmentItemService.unassignItem(item.getId());
            }

            item.setRosPackage(ros);
            ros.getIdentifiedItems().add(item);

            MaintenanceEntry maint = new MaintenanceEntry();
            maint.setEntryDate(new java.util.Date());
            maint.setItem(item);
            maint.setEntryText("Item added to ROS package " + ros.getTrackingNumber());

            item.getMaintenanceEntries().add(maint);

        }

        rosDao.save(ros);

        return ros;
    }

    public void deleteRos(int rosId) throws ServiceException {

        Ros ros = rosDao.getById(rosId);
        if (ros == null) {
            throw new ServiceException("message.ros.notfound", "Unable to find ROS with id#" + rosId);
        }

        for (EquipmentItem item: ros.getIdentifiedItems()) {

            item.setItemStatus(Status.Active);
            item.setRosPackage(null);

            MaintenanceEntry maint = new MaintenanceEntry();
            maint.setEntryDate(new java.util.Date());
            maint.setItem(item);
            maint.setEntryText("Item removed from deleted ROS package and status set to Active.");

            item.getMaintenanceEntries().add(maint);
            equipmentItemDao.save(item);

            maintenanceEntryDao.save(maint);
        }

        rosDao.delete(ros);
    }

    public void closeRos(int rosId) throws ServiceException {

        closeRos(rosId, new Date((new java.util.Date()).getTime()));
    }

    public void closeRos(int rosId, Date date) throws ServiceException {

        Ros ros = rosDao.getById(rosId);
        ros.setCloseDate(date);
        ros.setStatus(Status.Ros);

        for (EquipmentItem item : ros.getIdentifiedItems()) {


            item.setStatus(Status.Ros);

            if (item.getAssignedUser() != null) {
                item.setAssignedUser(null);
            }

            MaintenanceEntry maint = new MaintenanceEntry();
            maint.setEntryDate(new java.util.Date());
            maint.setItem(item);
            if (ros.getType() == RosType.Waiver) {
                maint.setEntryText("Item Waiver completed (Package: " + ros.getTrackingNumber() + ")");
            } else {
                maint.setEntryText("Item ROS completed (Package: " + ros.getTrackingNumber() + ")");
            }

            item.getMaintenanceEntries().add(maint);
            equipmentItemDao.save(item);

            maintenanceEntryDao.save(maint);

        }
    }

    public List<Ros> getAll() throws ServiceException {

        return rosDao.getAll();
    }

    public List<Ros> getAll(int adpeAccountId) throws ServiceException {

        AdpeAccount acct = adpeAccountDao.getById(adpeAccountId);
        if (acct==null) {
            throw new ServiceException("messages.ros.acct.notfound", "AdpeAccount id#" + adpeAccountId + " not found for getAll()");
        }
        return getAll(acct);
    }

    public List<Ros> getAll(AdpeAccount acct) throws ServiceException {

        return rosDao.getByAdpeAccount(acct);
    }
}
